﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;
using System.Diagnostics;
using System.Collections.ObjectModel;


namespace twilters
{
    /**
     * Interaction logic for Twilters
     */
    public partial class MainWindow : Window
    {
        private TwitterClient client;
        private DataStore dataStore;
        private ConfigurationHandler configuration;
        private String temp;
        private MinimizeToTray tray;
        private DispatcherTimer dispatcherTimer;

        // Currently active filter
        private Filter activeFilter;
        private PrivateData privateData;

        #region Thread handling variables
        private delegate void NoArgDelegate();
        private delegate void OneTweetListDelegate(List<Tweet> tweets);
        private delegate void OneFilterListDelegate(List<Filter> filters);
        private delegate void ActiveFilterDelegate(Filter filter);
        private delegate void SelectedFilterDelegate(Filter filter);
        #endregion

        #region Constructor and Destructor
        public MainWindow()
        {
            try
            {
                Init();
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        // destructor
        // all external resources must be closed here
        ~MainWindow()
        {
            client.Close();
            dataStore.Close();
        }
        #endregion

        private void Init()
        {
            InitializeComponent();
            tray = new MinimizeToTray();
            tray.Enable(this);

            // currently not implemented
            SettingsMenuItem.Visibility = Visibility.Hidden;

            configuration = new ConfigurationHandler();
            client = new TwitterClientImpl(configuration.baseUrl, configuration.searchUrl);

            dataStore = new DataStoreDb4o();
            dataStore.Open(configuration);

            // this should be configurable?
            // dataStore.purgeTweetCache();
            // dataStore.resetIDSequence();

            activeFilter = DefaultFilter();
            
            privateData = dataStore.loadPrivateData();

            Refresh();
        }

        #region UI listener functions

        private void Add_Filter_Click (object sender, RoutedEventArgs e)
        {
            FilterWindow fv = new FilterWindow(this, client, dataStore, null);
            fv.ShowDialog();
        }

        private void RemoveFilter_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                dataStore.deleteFilter((Filter)filterList.SelectedItem);
                Fetch_Filters();
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        private void Login_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (client.isLogged())
                {
                    Handle_Logout();
                }
                else
                {
                    Handle_Login();
                }
            }
            catch (Exception ex)
            {
                WindowUtil.displayError(ex.Message);
            }
        }

        private void Settings_Click(object sender, RoutedEventArgs e)
        {

        }

        private void Send_Click(object sender, RoutedEventArgs e)
        {
            temp = tweetMessage.Text;
            NoArgDelegate fetcher = new NoArgDelegate(this.PostTweetExecute);
            fetcher.BeginInvoke(null, null);
        }

        private void Update_Tweets(object sender, RoutedEventArgs e)
        {
            Load_Tweets_Execute();
        }

        private void tweetMessage_TextChanged(object sender, TextChangedEventArgs e)
        {
            int c = 140 - tweetMessage.Text.ToString().Length;
            tweetLabel.Content = c.ToString() + " characters left";
        }

        #endregion

        #region tweet handling functions

        private void Load_Tweets_Timer(object sender, EventArgs e)
        {
            Load_Tweets_Execute();
            // Forcing the CommandManager to raise the RequerySuggested event
            CommandManager.InvalidateRequerySuggested();
        }

        private void Load_Tweets_Execute()
        {
            NoArgDelegate fetcher = new NoArgDelegate(this.Load_Tweets);
            fetcher.BeginInvoke(null, null);
        }

        private void PostTweetExecute()
        {
            try
            {
                if (client.isLogged())
                {
                    client.postNewTweet(temp);
                    this.Dispatcher.BeginInvoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new NoArgDelegate(PostTweet)
                    );
                }
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        private void PostTweet()
        {
            tweetMessage.Text = "";
        }

        private void Load_Tweets()
        {
            try
            {
                if (client.isLogged())
                {
                    dataStore.storeTweets(client.findLatestTweets(TweetType.Friends));
                    this.Dispatcher.BeginInvoke(
                        System.Windows.Threading.DispatcherPriority.Normal,
                        new ActiveFilterDelegate(RunFilter),
                        activeFilter
                    );
                }
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        private void RunFilterExecute()
        {
            this.Dispatcher.BeginInvoke(
               System.Windows.Threading.DispatcherPriority.Normal,
               new ActiveFilterDelegate(RunFilter),
               activeFilter
            );
        }

        #endregion

        #region filter handling functions
        public void Reload_Filters()
        {
            NoArgDelegate fetcher = new NoArgDelegate(this.Fetch_Filters);
            fetcher.BeginInvoke(null, null);
        }

        private void Fetch_Filters()
        {
            try
            {
                List<Filter> filters = dataStore.findMyFilters(client.CurrentUserName());
                    try
                    {
                        this.Dispatcher.BeginInvoke(
                            System.Windows.Threading.DispatcherPriority.Normal,
                            new OneFilterListDelegate(UpdateFilters),
                            filters
                        );
                    }
                    catch (Exception exc)
                    {
                        WindowUtil.displayError(exc.Message);
                    }
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        private void RunFilter(Filter filter)
        {
            activeFilter = filter;
            UpdateUserInterface(dataStore.loadFilteredTweets(filter, client.CurrentUserName()));
        }

        #endregion

        #region global UI functions

        private void Handle_Logout()
        {
            StopTweetCaching();
            LoginMenuItem.Header = "Log in";
            client.logout();
            ClearUserInteface();
        }

        private void Handle_Login()
        {
            new LoginWindow(this, client, dataStore, privateData).ShowDialog();
        }

        private void UpdateUserInterface(List<Tweet> tweets)
        {
            if (client.isLogged())
            {
                tweetList.DataContext = tweets;
            }
        }

        private void ClearUserInteface()
        {
            tweetList.DataContext = new List<Tweet>();
            filterList.ItemsSource = new ObservableCollection<Filter>();
            SetUserFieldsEnabled(false);
        }

        private void SetUserFieldsEnabled(bool enabled)
        {
            SettingsMenuItem.IsEnabled = enabled;
            AddFilterButton.IsEnabled = enabled;
            //SortFiltersButton.IsEnabled = enabled;
            RemoveFilterButton.IsEnabled = enabled;
            reload.IsEnabled = enabled;
            SendButton.IsEnabled = enabled;
            tweetMessage.IsEnabled = enabled;
        }

        private void UpdateFilters(List<Filter> filters)
        {
            ObservableCollection<Filter> _filters = new ObservableCollection<Filter>();
            _filters.Add(DefaultFilter());
            foreach (Filter filter in filters)
            {
                _filters.Add(filter);
            }
            filterList.ItemsSource = _filters;
        }

        private void filterList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            RunFilter((Filter)filterList.SelectedItem);
        }

        public void Refresh()
        {
            try
            {
                if (client.isLogged())
                {
                    LoginMenuItem.Header = "Log out";
                    SetUserFieldsEnabled(true);
                    Load_Tweets_Execute();
                    Reload_Filters();
                    RunTweetCaching();
                }
                else
                {
                    ClearUserInteface();
                }
            }
            catch (Exception exc)
            {
                WindowUtil.displayError(exc.Message);
            }
        }

        #endregion

        private void RunTweetCaching()
        {
            if (dispatcherTimer == null)
            {
                dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
                dispatcherTimer.Tick += new EventHandler(Load_Tweets_Timer);
                //dispatcherTimer.Interval = new TimeSpan(0, 3, 10);
                dispatcherTimer.Interval = new TimeSpan(0, 0, 5);
            }
            if (!dispatcherTimer.IsEnabled)
            {
                dispatcherTimer.Start();
            }
        }

        private void StopTweetCaching()
        {
            if (dispatcherTimer.IsEnabled)
            {
                dispatcherTimer.Stop();
            }
        }

        private Filter DefaultFilter()
        {
            return new Filter("All", 0);
        }

    }
}
